[t:/]$ 지식_

kernel delay

2012/05/02

요즘 커널에도 똑같이 존재하는지는 모르겠다. 나중에 확인 해 보도록 하고..

참고여

http://www.makelinux.net/ldd3/chp-7-sect-3

1.

unsigned long timeout = jiffies + HZ;
schedule_timeout(timeout);

딜레이 중에 선점으로 치고 들어온다. 단, 컨텍스트 스위칭 뺑뺑이 돌고 오면서(부하 큼), 스케줄러 정책에 따라 밀릴 수도 있고(정확하지 않음).. 따라서 위의 딜레이를 루프 안에서 처리하면 해당 루프는 매우 느린 루프라고 가정해야 한다.

schedule_timeout_interruptible 는 딜레이 중에 시그널로 치고 들어올 수 있다.

HZ = 100 일 수도 있고 1000일 수도 있다.. 커널 코드 까봐야 안다..
2.6에서는 대충 1000으로 보면 된다.

HZ는 즉 1초다.

2.

그냥 스핀 딜레이를 보자.

unsigned long timeout = jiffies + HZ;
while (time_before(jiffies, timeout));

1초 짜리 딜레이다. 스핀 딜레이다. 위험하다.

time_before 함수는 도대체 뭔가.
jiffies의 오버플로우 때문이다.
HZ가 100이면 10ms 마다 1틱 증가하므로 언젠간 넘친다.

time_after(a,b); // a가 최신이면
time_before(a,b) // a가 옛날이면
time_after_eq(a,b);
time_before_eq(a,b)

위 함수들은 오버플로우를 반영해서 처리해준다. 업타임이 긴 시스템에서는 무조건 써야 한다.

64비트 jiffies도 있다.

u64 get_jiffies_64(void);  // 반드시 함수로 접근해서 쓴다

3.

디바이스 드라이버에서 종종 쓰는 딜레이다.

#include <linux/delay.h>

void mdelay(unsigned long milliseconds);
void udelay(unsigned long microseconds);
void ndelay(unsigned long nanoseconds);

스핀 루프다 -_-; 절대로 막 쓰면 안 된다. mdelay에 한해서 부팅 초기에 쓰는 건 괜찮다. 디바이스 안정화 시간이 필요한 경우들이 그렇다.

1번의 스핀루프를 다음 처럼 고치면 안전하다.

unsigned long timeout = jiffies + HZ;
while (time_before(jiffies, timeout)) {
    schedule(  );
}

다만 역시 선점으로 치고 들어오기 때문에 내 뜻대로 딜레이가 안 된다. 응답속도가 빨라야 하고, 폴링스런 루프안에 있다면 저렇게 schedule() 때리면 많이 느려진다.

4.

https://www.kernel.org/doc/htmldocs/device-drivers/API-wait-event-interruptible-timeout.html

#include <linux/wait.h>
wait_event(wq, condition)

long wait_event_timeout(wait_queue_head_t q, condition, long timeout);
long wait_event_interruptible_timeout(wait_queue_head_t q, condition, long timeout);

wait_event(wq, condition)
wait_event_interruptible(wq, condition)

wait_queue_head_t wait;

init_waitqueue_head (&wait);
wait_event_interruptible_timeout(wait, 0, delay);

timeout은 jiffies 값이므로 HZ가 100일때 1이면 10ms 이다.

그래도 함수를 쓰자.

#include <jiffies.h>

msecs_to_jiffies()
usecs_to_jiffies()

타임아웃으로 리턴되면 리턴값은 0이지만 이벤트로 리턴되면 리턴값은 남은 시간을 마이너스로 리턴한다.

5.

void msleep(unsigned int millisecs);    .. schedule_timeout()의 매크로
unsigned long msleep_interruptible(unsigned int millisecs);  .. schedule_timeout_interruptible의 매크로
void ssleep(unsigned int seconds)

6.

참고 http://forum.falinux.com/zbxe/?document_srl=533502 에서 가져온 것

if(!test_and_set_bit(0x01, &flags)) {
    wake_up_interruptible(&ewaitq);
}

…

wait_event(ewaitq, test_and_clear_bit(0x01, &flags));
timeout = wait_event_timeout(ewaitq, test_and_clear_bit(0x01, &flags), HZ);
wait_event_interruptible(ewaitq, test_and_clear_bit(0x01, &flags));
timeout = wait_event_interruptible_timeout(ewaitq, test_and_clear_bit(0x01, &flags), HZ);

더 많은 예제들을 참고하자.





공유하기













[t:/] is not "technology - root". dawnsea, rss